package com.example.form.controller;

import com.example.form.common.AppResult;
import com.example.form.common.ResultCode;
import com.example.form.config.AppConfig;
import com.example.form.exception.ApplicationException;
import com.example.form.model.User;
import com.example.form.service.IUserService;
import com.example.form.utils.MD5Util;
import com.example.form.utils.StringUtil;
import com.example.form.utils.UUIDUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Api(tags = "用户接口")//对controller进行API描述
@RestController//是controller,让spring管理起来,并且返回的数据是json格式的(数据在httpbody里面的
@RequestMapping("/user")//一级路径
@Slf4j
public class UserController {

    @Autowired
    private IUserService userService;//属性注入得到数据库操作的service层的接口类,个类实现了接口并且添加了@Service注解，被它实现得到的接口可以被属性注入。

    /**
     *
     * @param username 用户姓名
     * @param nickname 用户昵称
     * @param password 用户密码
     * @param passwordRepeat 确认密码
     * @return
     */
    @ApiOperation("用户注册")
    @PostMapping("/register")//二级路径
    public AppResult register(@ApiParam("用户名") @RequestParam("username") @NonNull String username,
                              @ApiParam("昵称") @RequestParam("nickname") @NonNull String nickname,
                              @ApiParam("密码") @RequestParam("password") @NonNull String password,
                              @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat){
        //2,判断密码和确认密码是否相等
        if (!password.equals(passwordRepeat)){
            return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);//两次密码输入不一致的错误
        }
        //3,准备数据
        User user=new User();
        user.setUsername(username);
        user.setNickname(nickname);
        //4,处理密码
        //生成盐
        String salt= UUIDUtil.UUID_32();
        //生成密码的密文
        String encryptPassword= MD5Util.md5Salt(password,salt);
        //设置密码和盐
        user.setPassword(encryptPassword);
        user.setSalt(salt);

        //5调用service层
        userService.createNormaluser(user);//数据库添加用户数据
        //返回成功
        return AppResult.success();
    }

    @ApiOperation("用户登录")
    @PostMapping("/login")
    public AppResult login(HttpServletRequest request,//获取和设置session
                           @ApiParam("用户名") @RequestParam("username") @NonNull String username,
                           @ApiParam("密码") @RequestParam("password") @NonNull String password){//这里已经校验参数了
        //1,调用service中的登录方法,获取登录的对象
        User user=userService.login(username,password);
        if(user==null){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());//打印用户不存在状态码日志
            //返回结果
            return AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS);//返回失败的结果
        }
        //2,若用户登录成功就把user对象设置到session中
        HttpSession session=request.getSession(true);//没有就创建session,有就拿
        session.setAttribute(AppConfig.USER_SESSION,user);//设置用户cookie,key是自定义的全局变量key
        //3,返回结果
        return AppResult.success();//成功的结果方法
    }

    @ApiOperation("获取用户信息")
    @GetMapping("/info")
    private AppResult getUserInfo(HttpServletRequest request,
                                  @ApiParam("⽤⼾Id")
                                  @RequestParam(value = "id", required = false) Long id){
        //根据传入的id的值,来选择user对象的获取方法
        User user=null;//先在外面定义user,要不然在if里面获取到了,在下面获取不到
        if(id==null){//代表前端没有传递来id参数
            //id为空,代表要从登录的session中获取当前登录用户的信息
            HttpSession session=request.getSession(false);//有就拿,没有也不创建,代表当前用户没有登录
            //判断session中的信息是否有效
            if(session==null||session.getAttribute(AppConfig.USER_SESSION)==null){//通过key获取存入的user
                //代表当前用户没有登录,返回错误信息
                return AppResult.failed(ResultCode.FAILED_FORBIDDEN);//返回自定义的禁止访问的异常
            }
            //session信息有效的时候,从session中获取用户信息
             user=(User) session.getAttribute(AppConfig.USER_SESSION);//通过key获取登录的时候存到session中的登录用户的信息
        }else {//传入的id有数据的时候,就调用service中的方法,通过id来查询用户信息
             user=userService.selectById(id);
        }
        //判断获取到的user对象是否有效
        if(user==null){
            return AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS);//返回自定义的用户不存在的异常
        }
        return AppResult.success(user);//把查询到的用户的信息返回回去
    }
    @ApiOperation("退出登录")
    @PostMapping("/loguot")
    public AppResult loguot(HttpServletRequest request){
        //获取session对象
        HttpSession session= request.getSession(false);//有就拿,没有也不创建
        //判断session是否有效
        if (session!=null){
            log.info("退出成功");
            //表示用户在登录状态,直接销毁session
            session.invalidate();//销毁当前登录用户的session
        }
        return AppResult.success("退出成功");//有session则退出,没有代表没有登录.也退出
    }

    @ApiOperation("修改个人信息")
    @PostMapping("/modifyInfo")
    public AppResult modifyInfo(HttpServletRequest request,//为了得到用户id
                                @ApiParam("⽤⼾名") @RequestParam(value = "username",required = false) String username,
                                @ApiParam("昵称") @RequestParam(value = "nickname",required = false) String nickname,
                                @ApiParam("性别") @RequestParam(value = "gender",required = false) Byte gender,
                                @ApiParam("邮箱") @RequestParam(value = "email",required = false) String email,
                                @ApiParam("电话号") @RequestParam(value = "phoneNum",required = false) String phoneNum,
                                @ApiParam("个⼈简介") @RequestParam(value = "remark",required = false) String remark){//接收参数,而且参数可为空
        //1,对参数进行非空校验(若全部为空的话,就不用执行动态SQL了,因为没有传递来要修改的参数
        if (StringUtil.isEmpty(username) && StringUtil.isEmpty(nickname)
            && StringUtil.isEmpty(email) && StringUtil.isEmpty(phoneNum)
            && StringUtil.isEmpty(remark) && gender == null){
            //返回错误信息
            return AppResult.failed("请输入参数");//可以自定义返回的错误的,这里是没有传递来要修改的数据
        }
        //2,从session中获取用户id
        HttpSession session=request.getSession(false);
        User user= (User) session.getAttribute(AppConfig.USER_SESSION);
        //3,封装要修改对象
        User updateUser=new User();
        updateUser.setId(user.getId());//用户id
        updateUser.setUsername(username);//用户名(登录名)
        updateUser.setNickname(nickname);//昵称
        updateUser.setGender(gender);//性别
        updateUser.setEmail(email);//邮箱
        updateUser.setPhoneNum(phoneNum);//电话
        updateUser.setRemark(remark);//个人简介
        //4,调用service方法
        userService.modifyInfo(updateUser);//通过用户id动态修改对应的属性
        //5,查询最新的用户信息(因为刚刚更新了)
        user=userService.selectById(user.getId());
        //6把最新的用户信息设置到session中去
        session.setAttribute(AppConfig.USER_SESSION,user);
        //返回结果
        return AppResult.success(user);//返回的是最新的user
    }
    @ApiOperation("修改密码")
    @PostMapping("/modifyPwd")
    public AppResult modifyPassword(HttpServletRequest request,
                                    @ApiParam("原密码") @RequestParam("oldPassword") @NonNull String oldPassword,
                                    @ApiParam("新密码") @RequestParam("newPassword") @NonNull String newPassword,
                                    @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat){
        //1,校验新密码与确认密码是否相同
        if(oldPassword.equalsIgnoreCase(newPassword)){
            //返回异常
            return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);//两次输入的密码不一致
        }
        //2,获取当前登录用户的信息(为了获取用户id)
        HttpSession session=request.getSession(false);
        User user= (User) session.getAttribute(AppConfig.USER_SESSION);
        //3,调用service
        userService.modifyPassword(user.getId(), newPassword,oldPassword);
        //4,销毁session(因为我们的密码已经变了)
        if(session!=null){//session存在
            session.invalidate();//销毁
        }
        //5,返回结果
        return AppResult.success();
    }
}
